package com.cloudsea.yunhaianalysis.service.impl;

import com.cloudsea.yunhaianalysis.service.ExternalApiService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ExternalApiServiceImpl implements ExternalApiService {

    private static final Logger log = LoggerFactory.getLogger(ExternalApiServiceImpl.class);

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ObjectMapper objectMapper;

    @Value("${api.qweather.key}")
    private String qweatherKey;

    @Value("${api.tianapi.key}")
    private String tianapiKey;

    // 使用线程安全的ConcurrentHashMap作为缓存
    private final Map<Integer, JsonNode> holidayCache = new ConcurrentHashMap<>();
    private final Map<LocalDate, Map<String, String>> forecastCache = new ConcurrentHashMap<>();

    // ------------------- 天气API调用 -------------------

    @Override
    public Map<String, String> getHistoricalWeather(LocalDate date) {
        String locationId = "101180701"; // 示例: 北京
        String dateStr = date.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String url = String.format("https://mj33jnub3r.re.qweatherapi.com/v7/historical/weather?location=%s&date=%s&key=%s",
                locationId, dateStr, qweatherKey);

        try {
            String jsonResponse = restTemplate.getForObject(url, String.class);
            JsonNode root = objectMapper.readTree(jsonResponse);
            if ("200".equals(root.path("code").asText())) {
                log.info("成功获取日期 [{}] 的历史天气。", date);
                return parseHistoricalWeather(root);
            } else {
                log.warn("获取历史天气失败，和风天气API返回错误: {}", jsonResponse);
            }
        } catch (Exception e) {
            log.error("调用历史天气API时发生异常, 日期: {}", date, e);
        }
        return getDefaultWeather();
    }

    @Override
    public Map<String, String> getWeatherForecast(LocalDate date) {
        if (forecastCache.containsKey(date)) {
            log.info("天气预报缓存命中，日期: {}", date);
            return forecastCache.get(date);
        }

        String locationId = "101180701"; // 示例: 北京
        String url = String.format("https://mj33jnub3r.re.qweatherapi.com/v7/weather/3d?location=%s&key=%s",
                locationId, qweatherKey);

        try {
            String jsonResponse = restTemplate.getForObject(url, String.class);
            JsonNode root = objectMapper.readTree(jsonResponse);
            if ("200".equals(root.path("code").asText())) {
                log.info("成功获取未来3天天气预报。");
                // 解析并缓存3天的预报
                for (JsonNode dailyForecast : root.path("daily")) {
                    LocalDate forecastDate = LocalDate.parse(dailyForecast.path("fxDate").asText());
                    Map<String, String> weatherFeatures = parseForecastWeather(dailyForecast);
                    forecastCache.put(forecastDate, weatherFeatures);
                }
                // 再次从缓存中获取目标日期的数据
                if (forecastCache.containsKey(date)) {
                    return forecastCache.get(date);
                }
            } else {
                log.warn("获取天气预报失败，和风天气API返回错误: {}", jsonResponse);
            }
        } catch (Exception e) {
            log.error("调用天气预报API时发生异常", e);
        }
        return getDefaultWeather();
    }

    // ------------------- 节假日API调用 -------------------

    @Override
    public Map<String, Object> getHolidayInfo(LocalDate date) {
        int year = date.getYear();
        try {
            if (!holidayCache.containsKey(year)) {
                String url = String.format("https://apis.tianapi.com/jiejiari/index?key=%s&date=%d", tianapiKey, year);
                String jsonResponse = restTemplate.getForObject(url, String.class);
                JsonNode root = objectMapper.readTree(jsonResponse);
                if (200 == root.path("code").asInt()) {
                    log.info("成功获取年份 [{}] 的节假日信息并缓存。", year);
                    holidayCache.put(year, root.path("result").path("list"));
                } else {
                    log.warn("获取节假日信息失败，天行数据API返回错误: {}", jsonResponse);
                }
            }

            JsonNode holidayList = holidayCache.get(year);
            if (holidayList != null) {
                // 天行数据的日期格式是 MMdd
                String dateStr = date.format(DateTimeFormatter.ofPattern("MMdd"));
                for (JsonNode holiday : holidayList) {
                    if (dateStr.equals(holiday.path("date").asText())) {
                        Map<String, Object> holidayInfo = new HashMap<>();
                        holidayInfo.put("isHoliday", true);
                        holidayInfo.put("holidayName", holiday.path("name").asText());
                        return holidayInfo;
                    }
                }
            }
        } catch (Exception e) {
            log.error("调用节假日API时发生异常, 年份: {}", year, e);
        }

        // 如果API失败或当天不是法定节假日，则根据周六日判断
        return getDefaultHolidayInfo(date);
    }

    // ------------------- 私有辅助方法 -------------------

    private Map<String, String> parseHistoricalWeather(JsonNode root) {
        Map<String, String> features = new HashMap<>();
        JsonNode daily = root.path("weatherDaily");
        features.put("maxTemp", daily.path("tempMax").asText("25"));
        features.put("minTemp", daily.path("tempMin").asText("15"));

        JsonNode hourly = root.path("weatherHourly");
        if (hourly.isArray() && !hourly.isEmpty()) {
            String weatherDay = "晴";
            String weatherNight = "晴";
            double totalPrecip = 0.0;
            int totalHumidity = 0;
            int count = 0;
            for (JsonNode hourData : hourly) {
                String time = hourData.path("time").asText();
                if (time.endsWith(" 08:00")) weatherDay = hourData.path("text").asText();
                if (time.endsWith(" 20:00")) weatherNight = hourData.path("text").asText();
                totalPrecip += hourData.path("precip").asDouble(0.0);
                totalHumidity += hourData.path("humidity").asInt(60);
                count++;
            }
            features.put("weatherDay", weatherDay);
            features.put("weatherNight", weatherNight);
            features.put("totalPrecip", String.valueOf(totalPrecip));
            features.put("avgHumidity", (count > 0) ? String.valueOf(totalHumidity / count) : "60");
        }
        return features;
    }

    private Map<String, String> parseForecastWeather(JsonNode dailyForecast) {
        Map<String, String> features = new HashMap<>();
        features.put("weatherDay", dailyForecast.path("textDay").asText("未知"));
        features.put("weatherNight", dailyForecast.path("textNight").asText("未知"));
        features.put("maxTemp", dailyForecast.path("tempMax").asText("25"));
        features.put("minTemp", dailyForecast.path("tempMin").asText("15"));
        return features;
    }

    private Map<String, String> getDefaultWeather() {
        log.warn("天气API调用失败或解析错误，使用默认天气值。");
        Map<String, String> defaultWeather = new HashMap<>();
        defaultWeather.put("maxTemp", "25");
        defaultWeather.put("minTemp", "15");
        defaultWeather.put("weatherDay", "未知");
        defaultWeather.put("weatherNight", "未知");
        defaultWeather.put("totalPrecip", "0.0");
        defaultWeather.put("avgHumidity", "60");
        return defaultWeather;
    }

    private Map<String, Object> getDefaultHolidayInfo(LocalDate date) {
        Map<String, Object> holidayInfo = new HashMap<>();
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) {
            holidayInfo.put("isHoliday", true);
            holidayInfo.put("holidayName", "周末");
        } else {
            holidayInfo.put("isHoliday", false);
            holidayInfo.put("holidayName", "工作日");
        }
        return holidayInfo;
    }
}